package com.example.consumptionrecords.util.qianfan;

import com.alibaba.fastjson.JSON;
import com.baidubce.qianfan.Qianfan;
import com.baidubce.qianfan.core.auth.Auth;
import com.baidubce.qianfan.model.chat.ChatResponse;
import com.baidubce.qianfan.model.console.ConsoleResponse;
import com.baidubce.qianfan.util.CollUtils;
import com.baidubce.qianfan.util.Json;
import com.baidubce.qianfan.util.StringUtils;
import com.example.consumptionrecords.entity.enums.GlobalConstants;
import com.example.consumptionrecords.exception.GlobalException;
import com.example.consumptionrecords.util.okhttp.OkHttpUtil;
import com.example.consumptionrecords.util.redis.RedisUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * hhzr9
 * 2024 \ 03 \ 28
 */

@Slf4j
@Component
public class QianFanUtil {

	@Value("${baidu.qianfan.api.api-key}")
	private String APP_API_KEY;

	@Value("${baidu.qianfan.api.secret-key}")
	private String APP_SECRET_KEY;

	private static final String ACCESS_KEY = "559d629e32844607a4ca83e18040f9e7";

	private static final String SECRET_KEY = "eded841fbec24804a70aad52392e5836";

	@Resource
	private RedisUtil redisUtil;

	private static final String AUTH_URL = "https://aip.baidubce.com/oauth/2.0/token?client_id=";

	private static final String CHAT_URL = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=";

	private static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().connectTimeout(15, TimeUnit.SECONDS)
			.writeTimeout(20, TimeUnit.SECONDS)
			.readTimeout(20, TimeUnit.SECONDS).build();

	/**
	 * 名称					类型		描述
	 * access_token			string		访问凭证
	 * expires_in			int			有效期，Access Token的有效期。说明：单位是秒，有效期30天
	 * error				string		错误码说明：响应失败时返回该字段，成功时不返回
	 * error_description	string		错误描述信息，帮助理解和解决发生的错误，说明：响应失败时返回该字段，成功时不返回
	 * session_key			string		暂时未使用，可忽略
	 * refresh_token		string		暂时未使用，可忽略
	 * scope				string		暂时未使用，可忽略
	 * session_secret		string		暂时未使用，可忽略
	 * @return access_token
	 */
	private String getAccessToken() {
		boolean exists = redisUtil.exists("qianfan_access_token");
		if (exists) {
			return (String) redisUtil.get("qianfan_access_token");
		} else {
			String syncResponse = OkHttpUtil.builder().url(AUTH_URL + APP_API_KEY + "&client_secret=" + APP_SECRET_KEY + "&grant_type=client_credentials")
					.addHeader("Content-Type", "application/json")
					.addHeader("Authorization", "Bearer ")
					.post(true)
					.sync();

			HashMap<String, String> map = JSON.parseObject(syncResponse, HashMap.class);
			String accessToken = map.get("access_token");
			if (StringUtils.isNotEmpty(accessToken)) {
				redisUtil.set("qianfan_access_token", accessToken, 30 * 24 * 60 * 60);
				return accessToken;
			} else {
				log.error("获取千帆access_token出错，错误：{}， 描述：{}", map.get("error"), map.get("error_description"));
				throw new GlobalException(GlobalConstants.QIANFAN_GET_ACCESS_TOKEN_ERR.getCode(), GlobalConstants.QIANFAN_GET_ACCESS_TOKEN_ERR.getMessage());
			}
		}
	}

	public String qianfanChat(String message) {
		Map<String, String> messages = new HashMap<>();
		messages.put("role", "user");
		messages.put("content", message);
		List<Map<String, String>> messagesList = new ArrayList<>();
		messagesList.add(messages);
		String syncResponse = OkHttpUtil.builder().url(CHAT_URL + this.getAccessToken())
				.addParam("temperature", 0.7F)
				.addParam("top_p", 0.9F)
				.addParam("messages", messagesList)
				.addParam("disable_search", false)
				.addParam("enable_citation", false)
				.addHeader("Content-Type", "application/json")
				.post(true)
				.sync();
		HashMap<String, String> map = JSON.parseObject(syncResponse, HashMap.class);
		String result = map.get("result");
		if (StringUtils.isNotEmpty(result)) {
			return result;
		} else {
			log.error("千帆对话出错，错误码：{}， 错误描述：{}", map.get("error_code"), map.get("error_msg"));
			throw new GlobalException(GlobalConstants.QIANFAN_TALK_ERR.getCode(), GlobalConstants.QIANFAN_TALK_ERR.getMessage());
		}
	}

	public String qianfanChatStream(String message) {
		// 使用安全认证AK/SK鉴权，替换下列示例中参数，安全认证Access Key替换your_iam_ak，Secret Key替换your_iam_sk
		Qianfan qianfan = new Qianfan(Auth.TYPE_OAUTH, APP_API_KEY, APP_SECRET_KEY);

		ChatResponse resp = qianfan.chatCompletion()
				.model("ERNIE-3.5-8K")
				.addMessage("user", message)
				.enableSystemMemory(true)
				.systemMemoryId("sm-h255eqqbr7urt9ae")
				.execute();
		modifySystemMemory(message, resp.getResult());
		return resp.getResult();
	}

	public static String createSystemMemory(String description) {
		return new Qianfan(ACCESS_KEY, SECRET_KEY).console()
				// 调用本文API，该参数值为固定值，无需修改；对应本文HTTP调用-请求说明-请求地址的后缀
				.route("/v2/memory")
				// 调用本文API，该参数值为固定值，无需修改；对应本文HTTP调用-请求说明-请求参数-Query参数的Action
				.action("CreateSystemMemory")
				// 需要传入参数的场景，可以自行封装请求类，或者使用Map.of()来构建请求Body
				// Java 8可以使用SDK提供的CollUtils.mapOf()来替代Map.of()
				// 对应本文HTTP调用-请求说明-请求参数-Body参数，具体使用请查看Body参数说明，根据实际使用选择参数
				.body(CollUtils.mapOf("appId", "47745242", "description", description))
				.execute(String.class)
				.getResult();

	}

	public String describeSystemMemory() {
		Qianfan qianfan = new Qianfan(ACCESS_KEY, SECRET_KEY);

		ConsoleResponse<Map<String, Object>> response = qianfan.console()
				// 调用本文API，该参数值为固定值，无需修改；对应本文HTTP调用-请求说明-请求地址的后缀
				.route("/v2/memory")
				// 调用本文API，该参数值为固定值，无需修改；对应本文HTTP调用-请求说明-请求参数-Query参数的Action
				.action("DescribeSystemMemories")
				// 需要传入参数的场景，可以自行封装请求类，或者使用Map.of()来构建请求Body
				// Java 8可以使用SDK提供的CollUtils.mapOf()来替代Map.of()
				// 对应本文HTTP调用-请求说明-请求参数-Body参数，具体使用请查看Body参数说明，根据实际使用选择参数
				.body(CollUtils.mapOf(
						"appId", "47745242"
				))
				.execute();
		return Json.serialize(response);
	}

	public static Map<String, Object> describeSystemMemory(String systemMemoryId) {
		return new Qianfan(ACCESS_KEY, SECRET_KEY).console()
				.route("/v2/memory")
				.action("DescribeSystemMemory")
				.body(CollUtils.mapOf(
						"systemMemoryId", systemMemoryId
				))
				.execute()
				.getResult();
	}

	public static String deleteSystemMemory(String systemMemoryId) {
		return new Qianfan(ACCESS_KEY, SECRET_KEY).console()
				// 调用本文API，该参数值为固定值，无需修改；对应本文HTTP调用-请求说明-请求地址的后缀
				.route("/v2/memory")
				// 调用本文API，该参数值为固定值，无需修改；对应本文HTTP调用-请求说明-请求参数-Query参数的Action
				.action("DeleteSystemMemory")
				// 需要传入参数的场景，可以自行封装请求类，或者使用Map.of()来构建请求Body
				// Java 8可以使用SDK提供的CollUtils.mapOf()来替代Map.of()
				// 对应本文HTTP调用-请求说明-请求参数-Body参数，具体使用请查看Body参数说明，根据实际使用选择参数
				.body(CollUtils.mapOf("systemMemoryId", systemMemoryId))
				.execute(String.class)
				.getResult();
	}

	public static void modifySystemMemory(String userMessage, String systemMessage) {
		Qianfan qianfan = new Qianfan(ACCESS_KEY, SECRET_KEY);
		ConsoleResponse<Map<String, Object>> resp = qianfan.console()
				.route("/v2/memory")
				.action("ModifySystemMemory")
				.body(CollUtils.mapOf(
						"systemMemoryId", "sm-h255eqqbr7urt9ae",
						"memories", new Map[][]{
								{
										CollUtils.mapOf(
												"role", "user",
												"content", userMessage
										),
										CollUtils.mapOf(
												"role", "system",
												"content", systemMessage
										)
								},
						}
				))
				.execute();

	}
}
